import { IServiceApi, IServiceSendOptions, useService } from "@/lib/Service";
import {  queueCallFunc, queueCallRaceAll } from "elmer-common";
import { useCallback, useState } from "react";

export type RequestMode = "RaceAll"|"QueueList";

export type IServiceSendOptionConfig = IServiceSendOptions & {
    name: string;
    retryCount?: number;
    shouldRetry?: Function;
    withoutErrorHandle?: boolean;
}

const formatResponse = (responseData: any) => {
    const nextData: any = {};
    if(responseData) {
        Object.keys(responseData).forEach((dataKey: string) => {
            const curData = responseData[dataKey];
            if(/^QueueCall_/.test(curData?.statusCode)) {
                nextData[dataKey] = curData.exception;
            } else {
                nextData[dataKey] = curData;
            }
        })
    }
    return nextData;
};

const callApiWithRetry = (api:IServiceApi, endPoint: any, retryCount: number) => {
    return new Promise((resolve, reject) => {
        api.send(endPoint).then((responseData: any) => {
            resolve(responseData);
        }).catch((error) => {
            const retry = typeof endPoint.shouldRetry === "function" ? endPoint.shouldRetry(error) : true;
            if(retryCount > 0 && retry) {
                const timeHandle = setTimeout(() => {
                    callApiWithRetry(api, endPoint, retryCount - 1)
                        .then(resolve).catch(reject);
                    clearTimeout(timeHandle);
                }, 1000);
            } else {
                reject({
                    ...error,
                    withoutErrorHandle: endPoint.withoutErrorHandle
                });
            }
        });
    });
};
const useApiCall = (reqEndPoints: IServiceSendOptionConfig[], callListMode: RequestMode, throwException?: boolean) => {
    const serviceApi = useService();
  
    const [ throwExceptionWithError ] = useState(() => {
        return typeof throwException === "boolean" ? throwException : true;
    });
    const [ listApiCall ] = useState(() => callListMode === "RaceAll" ? queueCallRaceAll : queueCallFunc);
    const createApiCall = useCallback((endpoints: IServiceSendOptionConfig[]) => {
        return () => {
            return new Promise((resolve, reject) => {
                const successStatus: any = {};
                listApiCall(endpoints as any[], ((_opt: any, param: any) => {
                    return new Promise((_resolve, _reject) => {
                        callApiWithRetry(serviceApi, param, param.retryCount || 0)
                            .then((responseData: any) => {
                                successStatus[param.name] = responseData;
                                _resolve(responseData);
                            }).catch(_reject);
                    });
                }) as any, {
                    throwException: throwExceptionWithError,
                    paramConvert: (param: any, index: number) => {
                        return {
                            params: param,
                            id: param.name || index
                        }
                    }
                }).then((finalResponseData: any) => {
                    resolve(formatResponse(finalResponseData));
                }).catch((error: any) => {
                    //根据已成功请求创建重试回调方法
                    const successKeys = Object.keys(successStatus);
                    const retryCall = createApiCall(
                        endpoints.filter((v) => !successKeys.includes(v.name))
                    );
                    
                    setCallApiList(() => retryCall);
                    reject(error.exception);
                });
            });
        };
    }, []);
    const [ callApiList, setCallApiList ] = useState(() => createApiCall(reqEndPoints));
    return callApiList;
  
};


export default useApiCall;
